## 学习makefile的笔记
## 功能:使用对应编译器编译目录下的相应后缀的文件

# 编译参数
# 	1.-MM 表示自动寻找源文件中包含的头文件->编译器提供的功能
#	2.-Wall 表示打开所有的编译警告
#	3.-Werror 表示将警告都当错误处理
CFLAGS  =  -Wall -Werror -g -rdynamic -pthread
CPPFLAGS =  -Wall -Werror -g -rdynamic -pthread

#PROGS = main	# 使用 = 运算符，后面的变量可以是前文未出现过
CC:=gcc			# 使用 := 运算符，只能使用前文已定义的变量
CXX?=g++		# 使用 ?= 运算符，如果变量没定义过就赋值，否则啥也不做

LIBS += -lm	# 使用 += 运算符，追加变量，如果没定义过会自动变成 = 运算符
INC := -I ./lib/include

AR:=ar
RM:=rm
OBJ_DIR=./
depends_c = $(wildcard  *.c)		#寻找所有的.c文件
depends_cc = $(wildcard  *.cc) 		#寻找所有的.cc文件
depends_cpp = $(wildcard  *.cpp) 	#寻找所有的.cpp文件

c_objs = $(addprefix $(OBJ_DIR)/,$(depends_c:.c=.o))			#将目标中的.c替换成.o
cc_objs =$(addprefix $(OBJ_DIR)/,$(depends_cc:%.cc=%.o))	#静态模式，将目标中的.cc替换成.o
cpp_objs = $(addprefix $(OBJ_DIR)/,$(depends_cpp:%.cpp=%.o))	#静态模式，将目标中的.cc替换成.o
d_objs = $(addprefix $(OBJ_DIR)/,$(depends_cpp:.cpp=.d))
PROGS = $(depends_cpp:%.cpp=%)

#为目标一般没有依赖文件，我们并不生成all，所以指定all仅仅为一个标签
#.PHONY:all
#放在第一个会成为默认目标
all: $(cpp_objs) $(PROGS) $(d_objs)

#所有依赖的目标集可以用 自动化变量 '$<'表示
$(PROGS): ${c_objs} ${cc_objs} ${c_objs}
	$(CXX) $^  $(addprefix $(OBJ_DIR)/,$@.o) -o $@  $(CFLAGS) $(CPPFLAGS) $(LIBS) $(INC)


# GNU组织建议把编译器为每一个源文件的自动生成的依赖关系放到一个文件中，为每一个 "name.c"的文件都生成一个"name.d"的makefile文件
# 即 [.d] 文件中存放对应 [.c] 文件的依赖关系
# 符号 - 表示如果没有对应的[.d]文件则忽略,继续执行,不报错
-include $(d_objs)
# 第1行：所有的[.d]文件依赖于[.c]文件
# 第2行：删除所有的目标，也就是[.d]文件
# 第3行：为每一个依赖文件(.c文件) '$<' 生成依赖文件 $@.$$$$是一个随机编号
# 第4行：sed->s命令：用斜线指定的第二个字符串替换第一个字符串，g表替换所有匹配文本
#		效果就是将 main.o : main.c defs.h 替换成 main.o main.d : main.c defs.h
# 第5行：删除临时文件
$(d_objs): $(cpp_objs)
	@set -e; rm -f $@; \
	 $(CXX) -MM $(CPPFLAGS) $(subst .d,.cpp,$(notdir $@)) >  $@.$$$$; \
     sed 's,\($(notdir $*)\)\.o[ :]*,$*\.o $@ : ,g' < $@.$$$$ > $@; \
     rm -f $@.$$$$


${c_objs}:${depends_c}
	$(CC) -c $(notdir $(subst .o,.c,$@)) -o $@  $(CFLAGS) $(LIBS) $(INC)

${cc_objs}:${depends_cc}
	$(CXX)-c $(notdir $(subst .o,.cc,$@)) -o $@  $(CPPFLAGS) $(LIBS) $(INC) 

${cpp_objs}:${depends_cpp}
	$(CXX) -c $(notdir $(subst .o,.cpp,$@)) -o $@ $(CPPFLAGS) $(LIBS) $(INC)

.PHONY:clean	#避免文件重名，显示指明伪目标
clean:
	-rm -rf $(c_objs) $(cc_objs) $(PROGS) $(d_objs) *.out *.o main ./objs/* ./objs/*.d ./objs/*.d.*
